import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.regex.Pattern.compile;

/**
 * @author shun
 */
public class StandardBuilder {
    private Standard standard = new Standard();
    private JSONObject seachResult = null;
    private Boolean ready = false;
    private static Scanner sc = new Scanner(System.in);
    private static Properties TYPE = new Properties();
    private static Properties PROVINCE = new Properties();
    private static Properties SPECIALTY = new Properties();
    private static HashMap<String, String> QUERY = new HashMap();

    static {
        Console console = System.console();
        if (console != null) {
            sc = new Scanner(console.reader());
        } else {
            System.out.println("Console is unavailable");
        }
        try {
            TYPE.load(new FileReader("type.properties"));
            PROVINCE.load(new FileReader("province.properties"));
            SPECIALTY.load(new FileReader("specialty.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        QUERY.put("module", "criterion");
        QUERY.put("categoryId", "115");//类别
        QUERY.put("keyword", null);//关键字
        QUERY.put("catalogs", "0");//专业
        QUERY.put("searchType", "3");//按书名和编号搜索
        QUERY.put("areaId", "0");//地区
        QUERY.put("tags", "");
        QUERY.put("timespan", "");
        QUERY.put("page", "1");
    }

    public StandardBuilder() {
        try {
            init();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * 从控制台读取数据，初始化对象
     */
    private void init() {
        HashMap<String, String> query = new HashMap<>(QUERY);
        System.out.print("输入书名或编号：");
        String keyword = sc.nextLine();
        query.put("keyword", keyword);
        if (keyword.isEmpty()) {
            return;
        }
        while (true) {
            System.out.println("设置搜索条件 -数字[设置] -Enter[完成]");
            String type = TYPE.getProperty(query.get("categoryId"));
            System.out.println("0 类别 : " + type);
            String specialty = SPECIALTY.getProperty(query.get("catalogs"));
            System.out.println("1 专业 : " + specialty);
            String province = PROVINCE.getProperty(query.get("areaId"));
            System.out.println("2 地区 : " + province);
            String line = sc.nextLine();
            if (line.isEmpty()) {
                break;
            }
            switch (Integer.parseInt(line.trim())) {
                case 0:
                    setQuery(query, "categoryId", TYPE);
                    break;
                case 1:
                    System.out.println("选择专业:" + specialty);
                    if (!(type.equals("法规公告") || type.equals("地方法规"))) {
                        setQuery(query, "catalogs", SPECIALTY);
                    } else {
                        setQuery(query, "catalogs", null);
                    }
                    break;
                case 2:
                    System.out.println("选择地区:" + province);
                    if (type.equals("地方法规")) {
                        setQuery(query, "areaId", PROVINCE);
                    } else {
                        setQuery(query, "areaId", null);
                    }
                    break;
                default:
                    System.out.println("没有此选项");
                    break;
            }
        }
        seachResult = search(query);
        if (seachResult == null) {
            return;
        }
        //设置基本信息
        standard.setSpecialties(seachResult.get("Catalogs").toString().split(","));
        standard.setCategory(seachResult.get("CategoryName").toString());
        standard.setArea(seachResult.get("Area").toString().split(" ")[0]);
        Matcher m = compile("^(?<name>[\\W]+)(?<id>.+?)$").matcher(seachResult.get("Title").toString());
        if (m.find()) {
            String name = m.group("name").replace("[附条文说明]", "");
            String id = m.group("id");
            standard.setName(name);
            standard.setId(id != null ? id : name);
        }
        String[] arr = {"规范名称：", "规范编号："};
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + (i == 0 ? standard.getName() : standard.getId()) + "  是否修改 -Y[是] -Enter[否]");
            String s = sc.nextLine();
            if ("Y".equals(s) || "y".equals(s)) {
                System.out.print(arr[i]);
                s = sc.nextLine();
                if (!s.isEmpty()) {
                    switch (i) {
                        case 0:
                            standard.setName(s);
                            break;
                        case 1:
                            standard.setId(s);
                            break;
                    }
                }
            }
        }
        ready = true;
    }

    /**
     * 运行
     */
    public void run() throws IOException {
        if (!ready) {
            return;
        }
        System.out.println("正在获取资源...");
        String url = "http://www.jianbiaoku.com/webarbs/book/" + seachResult.get("Sid") + "/" + seachResult.get("ChapterId") + ".shtml";
        Document document = HttpUtil.getDocument(url);
        //设置目录
        setCatalog(document);
        //输出规范概要
        FileOutputStream fos = new FileOutputStream("_summary.json",true);
        final BufferedWriter writerStandard = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 1024);
        writerStandard.write(JSON.toJSONString(standard));
        writerStandard.newLine();
        writerStandard.flush();
        writerStandard.close();

        System.out.println(standard.getName() + "开始下载...");
        scanPage();
        System.out.println(standard.getName() + "下载完成！");
    }

    /**
     * 设置参数
     *
     * @param query    需要设置的参数对象
     * @param describe query 的 key
     * @param props    参数集
     */
    private void setQuery(Map<String, String> query, String describe, Properties props) {
        if (props == null) {
            props = new Properties();
            props.put("0", "全部");
        }
        ArrayList<Map.Entry<Object, Object>> entries = new ArrayList<>(props.entrySet());
        for (int i = 0; i < entries.size(); i++) {
            System.out.println(i + " : " + entries.get(i).getValue());
        }
        String input = sc.nextLine();
        try {
            Integer i = Integer.parseInt(input);
            if (i > -1 && i < entries.size()) {
                query.put(describe, (String) entries.get(i).getKey());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        Object type = TYPE.get(query.get("categoryId"));
        if (!(type.equals("地方法规") || type.equals("全部"))) {
            query.put("areaId", "0");
        }
        if (type.equals("法规公告") || type.equals("地方法规")) {
            query.put("catalogs", "0");
        }
    }

    /**
     * 获取搜索结果
     *
     * @param props
     * @return JSONObject对象
     */
    public JSONObject search(Map<String, String> props) {
        if (props == null) {
            return null;
        }
        System.out.println("正在搜索可下载资源...");
        String url = "http://s.jianbiaoku.com/sou/home/sitesearch";
        ArrayList<BasicNameValuePair> list = new ArrayList<>();
        for (String key : props.keySet()) {
            list.add(new BasicNameValuePair(key, props.get(key)));
        }
        String str = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            CloseableHttpClient client = HttpClients.createDefault();
            httpPost.setEntity(new UrlEncodedFormEntity(list, "utf-8"));
            CloseableHttpResponse response = client.execute(httpPost);
            HttpEntity entity = response.getEntity();
            str = EntityUtils.toString(entity, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (str == null) {
            System.out.println("没有搜索到结果");
            return null;
        }
        JSONObject obj = JSONObject.parseObject(str);
        if (Integer.parseInt(obj.get("TotalCount").toString()) < 1) {
            return null;
        }
        JSONArray arr = obj.getJSONArray("Datas");
        for (int i = 0; i < arr.size(); i++) {
            JSONObject tmp = arr.getJSONObject(i);
            String abolish = (Boolean) tmp.get("Abolish") ? "[废止]" : "";
            System.out.println(i + " : " + abolish + tmp.get("Title"));
        }
        Integer i = -1;
        while (true) {
            System.out.print("输入 -数字[选择文件] -Exit[退出]：");
            String input = sc.nextLine();
            if (!"exit".equals(input.toLowerCase())) {
                try {
                    i = Integer.parseInt(input);
                    return arr.getJSONObject(i);
                } catch (Exception e) {
                    System.out.println("需要输入对应数字编号");
                }
                continue;
            }
            return null;
        }
    }

    /**
     * 获取目录集合、url集合
     *
     * @param doc XML对象
     * @return [目录集合、url集合]
     */
    private void setCatalog(Document doc) {
        final String DOMAIN = "http://www.jianbiaoku.com";
        Elements elements = doc.select("ul.book_catalog li");
        ArrayList<Standard.Catalog> catalogs = new ArrayList<>();
        for (int i = 0; i < elements.size(); i++) {
            String level = elements.get(i).attr("data-level");
            Elements a = elements.get(i).select("a");
            if (a.size() > 0) {
                String title = a.get(0).attr("title");
                String url = DOMAIN + a.get(0).attr("href");
                if ("3".equals(level)) {
                    HashMap<String, String> sub = new HashMap<>(1);
                    sub.put("title", title);
                    sub.put("url", url);
                    catalogs.get(catalogs.size() - 1).getSubCatalogs().add(sub);
                } else {
                    catalogs.add(new Standard().new Catalog(title, url));
                }
            }
        }
        standard.setCatalog(catalogs);
    }

    /**
     * 获取条文页面数据
     *
     * @return 返回条文List集合
     */
    private void scanPage() throws IOException {
        FileOutputStream fos = new FileOutputStream(standard.getName() + ".json");
        final BufferedWriter writerProvisions = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 1024);
        boolean isExplanatory = false;
        for (int i = 0; i < standard.getCatalog().size(); i++) {
            System.out.println(standard.getName()+" 当前进度：" + i + "/" + standard.getCatalog().size());
            Standard.Catalog catalog = standard.getCatalog().get(i);
            isExplanatory |= "条文说明".equals(catalog.getTitle());
            ArrayList<Map<String, String>> tmp = new ArrayList<>();
            if (catalog.getSubCatalogs().size() == 0) {
                Map<String, String> map = new HashMap<>();
                map.put("url", catalog.getUrl());
                map.put("title", catalog.getTitle());
                tmp.add(map);
            } else {
                tmp = catalog.getSubCatalogs();
            }
            for (Map<String, String> page : tmp) {
                Document doc = HttpUtil.getDocument(page.get("url"));
                Elements elements = doc.select("div.book_content>p");
                boolean check1 = true;
                for (int j = 0; elements != null && check1 && j < elements.size(); j++) {
                    String html = elements.get(j).html().trim();
                    check1 &= html.matches("^(\\s*<span.*?>\\s*[^<>]*\\s*</span>\\s*)*?|(\\s*<img.*?>\\s*)*?$");
                }
                if (check1) {
                    List<Provision> provisions = scanMode1(elements, page.get("title"), catalog.getTitle(), isExplanatory);
                    for (Provision p : provisions) {
                        writerProvisions.write(JSON.toJSONString(p));
                        writerProvisions.newLine();
                        writerProvisions.flush();
                    }
                    continue;
                }
//                Elements check2 = doc.select("div.book_content:has(>p:has(br,strong))");
//                if (check2.size() > 0) {
//                    list.addAll(scanMode2(catalog));
//                    continue;
//                }
            }
        }
        writerProvisions.close();
    }

    /**
     * 方式1:页面格式 div>p>span>...
     *
     * @param elements      页面节点 p
     * @param title         录标题
     * @param upTitle       上一级目录标题
     * @param isExplanatory 是否是条文说明
     * @return 条文List集合
     */
    private List<Provision> scanMode1(Elements elements, String title, String upTitle, boolean isExplanatory) {
        ArrayList<Provision> provisions = new ArrayList<>();
        final Pattern PATTERN_ID = compile("^(?<sn>[\\dA-Z]+?．[\\dA-Z]+?．[\\dA-Z]+?)\\s+");
        //获取规范具体条文
        Provision provision = new Provision();
        provision.setSn(title);
        provision.setStandard(standard.getId());
        provision.setExplanatory(isExplanatory);
        for (int i = 0; i < elements.size(); i++) {
            String text = elements.get(i).text().trim();
            if (!text.isEmpty() && !text.equals(title) && !text.equals(upTitle)) {
                Matcher matcher = PATTERN_ID.matcher(text);
                if (matcher.find()) {
                    //将上一条记录加到集合
                    if (provision.getContent().size() > 0) {
                        provisions.add(provision.duplicate());
                    }
                    //初始化一条新记录
                    boolean fw2 = elements.get(i).select("span.fw2").size() > 0;
                    provision.setEnforced(fw2);
                    provision.setContent(new ArrayList<>());
                    provision.setSn(matcher.group("sn").replaceAll("．","."));
                    text = matcher.replaceFirst("").trim();
                }
                //赋值到给上一条文
                provision.getContent().add(text);
            }
            //添加<img src="...">标签，src指向资源网站
            Elements img = elements.get(i).getElementsByTag("img");
            for (int k = 0; k < img.size(); k++) {
                provision.getContent().add(img.get(k).toString());
            }
        }
        //将最后一条记录加入集合
        provisions.add(provision.duplicate());
        return provisions;
    }

    /**
     * 方式2:页面格式 div.book_content>p:has(br,strong)
     *
     * @param catalog 规范目录
     * @return 条文List集合
     */
    private List<Provision> scanMode2(Standard.Catalog catalog) {
        ArrayList<Provision> provisions = new ArrayList<>();
////按行拆分,处理网页<p>1.0.1...<br>1.0.2...</>的情形
//        for (int j = elements.size()-1; j >-1; j--) {
//            String html = elements.get(j).html();
//            if(html.contains("<br>")){
//                String[] split = html.split("<br>");
//                elements.remove(j);
//                int empt=0;
//                for (int m = 0; m < split.length; m++) {
//                    String ele = split[m].trim();
//                    if(!ele.isEmpty()) {
//                        elements.add(m+j-empt,new Element(ele) );
//                    }else {
//                        empt++;
//                    }
//                }
//            }
//        }
//        System.out.println(elements);
//        ArrayList<Provision> page = page(elements, standard);
//        write(page, writerProvisions);
        return provisions;
    }
}
